package org.obp.data.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.obp.data.result.PageResult;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName ObjectUtils
 * @Description 对象相关工具类
 */
@Slf4j
public class ObjectUtils {

    public interface CopyHandler<S, T> {

        void execute(S source, T target);

    }

    public static <S, T> T copy(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            T target = targetClass.newInstance();
            BeanUtils.copyProperties(source, target);
            return target;
        } catch (Exception e) {
            log.error("copy fail", e);
            throw new RuntimeException("copy bean failed");
        }
    }

    public static <S, T> T copy(S source, Class<T> targetClass, CopyHandler<S, T> handler) {
        try {
            T target = copy(source, targetClass);
            if (source != null) {
                handler.execute(source, target);
            }
            return target;
        } catch (Exception e) {
            log.error("copy fail", e);
            throw new RuntimeException("copy bean failed");
        }
    }

    public static <S, T> T copy(S source, Class<T> targetClass, CopyHandler<S, T> handler, int index) {
        try {
            T target = copy(source, targetClass);
            if (source != null) {
                handler.execute(source, target);
            }
            return target;
        } catch (Exception e) {
            log.error("exception index:{}, message:{}", index, e.getMessage(), e);
            throw new RuntimeException("copy bean failed");
        }
    }

    public static <S, T> List<T> copyList(List<S> sourceList, Class<T> targetClass) {
        List<T> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetList;
        }
        for (S source : sourceList) {
            targetList.add(copy(source, targetClass));
        }
        return targetList;
    }

    public static <S, T> List<T> copyList(List<S> sourceList, Class<T> targetClass, CopyHandler<S, T> handler) {
        List<T> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetList;
        }
        for (int i = 0; i < sourceList.size(); i++) {
            targetList.add(copy(sourceList.get(i), targetClass, handler, i));
        }
        return targetList;
    }

    public static <S, T> PageResult<T> copyPage(PageResult<S> sourcePageResult, Class<T> targetClass) {
        List<T> targetList = new ArrayList<>();
        PageResult<T> targetPageResult = new PageResult<>();
        List<S> sourceList = sourcePageResult.getData();
        targetPageResult.setPageParam(sourcePageResult.getPageParam());
        targetPageResult.setTotalPage(sourcePageResult.getTotalPage());
        targetPageResult.setTotalCount(sourcePageResult.getTotalCount());
        targetPageResult.setData(new ArrayList<>());
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetPageResult;
        }
        for (S source : sourceList) {
            targetList.add(copy(source, targetClass));
        }
        targetPageResult.setData(targetList);
        return targetPageResult;
    }

    public static <S, T> PageResult<T> copyPage(PageResult<S> sourcePageResult, Class<T> targetClass, CopyHandler<S, T> handler) {
        List<T> targetList = new ArrayList<>();
        PageResult<T> targetPageResult = new PageResult<>();
        List<S> sourceList = sourcePageResult.getData();
        targetPageResult.setPageParam(sourcePageResult.getPageParam());
        targetPageResult.setTotalPage(sourcePageResult.getTotalPage());
        targetPageResult.setTotalCount(sourcePageResult.getTotalCount());
        targetPageResult.setData(new ArrayList<>());
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetPageResult;
        }
        for (int i = 0; i < sourceList.size(); i++) {
            targetList.add(copy(sourceList.get(i), targetClass, handler, i));
        }
        targetPageResult.setData(targetList);
        return targetPageResult;
    }


    public static <S, T> T copyDeep(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            String json = JSON.toJSONString(source);
            return JSON.parseObject(json, targetClass);
        } catch (Exception e) {
            log.error("copy fail", e);
            throw new RuntimeException("copy bean failed");
        }
    }

    public static <S, T> T copyDeep(S source, Class<T> targetClass, CopyHandler<S, T> handler) {
        try {
            T target = copyDeep(source, targetClass);
            if (source != null) {
                handler.execute(source, target);
            }
            return target;
        } catch (Exception e) {
            log.error("copy fail", e);
            throw new RuntimeException("copy bean failed");
        }
    }

    public static <S, T> List<T> copyListDeep(List<S> sourceList, Class<T> targetClass) {
        List<T> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetList;
        }
        for (S source : sourceList) {
            targetList.add(copyDeep(source, targetClass));
        }
        return targetList;
    }

    public static <S, T> List<T> copyListDeep(List<S> sourceList, Class<T> targetClass, CopyHandler<S, T> handler) {
        List<T> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetList;
        }
        for (S source : sourceList) {
            targetList.add(copyDeep(source, targetClass, handler));
        }
        return targetList;
    }

    public static <S, T> PageResult<T> copyPageDeep(PageResult<S> sourcePageResult, Class<T> targetClass) {
        List<T> targetList = new ArrayList<>();
        PageResult<T> targetPageResult = new PageResult<>();
        List<S> sourceList = sourcePageResult.getData();
        targetPageResult.setPageParam(sourcePageResult.getPageParam());
        targetPageResult.setTotalCount(sourcePageResult.getTotalCount());
        targetPageResult.setData(new ArrayList<>());
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetPageResult;
        }
        for (S source : sourceList) {
            targetList.add(copyDeep(source, targetClass));
        }
        targetPageResult.setData(targetList);
        return targetPageResult;
    }

    public static <S, T> PageResult<T> copyPageDeep(PageResult<S> sourcePageResult, Class<T> targetClass, CopyHandler<S, T> handler) {
        List<T> targetList = new ArrayList<>();
        PageResult<T> targetPageResult = new PageResult<>();
        List<S> sourceList = sourcePageResult.getData();
        targetPageResult.setPageParam(sourcePageResult.getPageParam());
        targetPageResult.setTotalCount(sourcePageResult.getTotalCount());
        targetPageResult.setData(new ArrayList<>());
        if (CollectionUtils.isEmpty(sourceList)) {
            return targetPageResult;
        }
        for (S source : sourceList) {
            targetList.add(copyDeep(source, targetClass, handler));
        }
        targetPageResult.setData(targetList);
        return targetPageResult;
    }

}
